﻿Public Class clsAppContext
    Inherits ApplicationContext

#Region " Storage "

    Private WithEvents MainMenu As ContextMenuStrip
    Private WithEvents mnuArchives As ToolStripMenuItem
    Private WithEvents mnuImport As ToolStripMenuItem
    Private WithEvents mnuViewLog As ToolStripMenuItem
    Private WithEvents mnuHelp As ToolStripMenuItem
    Private WithEvents mnuAutoStart As ToolStripMenuItem
    Private WithEvents mnuSep1 As ToolStripSeparator
    Private WithEvents mnuExit As ToolStripMenuItem
    Private Property AutoBackupActivated As Boolean
    Private Property AutoBackupFolder As String
    Private Property AutoBackupTime As Date
    Private Property AutoImportActivated As Boolean
    Private Property AutoImportTimeList As New List(Of Date)
    Private WithEvents TaskTimer As New Timer

    Const WRDBShortcut As String = "WRDB Task Scheduler"
    Const WRDBShortcutOld As String = "WRDB Scheduled Tasks"

#End Region

#Region " Constructor "

    Public Sub New()
        'Initialize the menus
        mnuArchives = New ToolStripMenuItem("Scheduled Archives", My.Resources.SaveAllHS)
        mnuImport = New ToolStripMenuItem("Scheduled Imports", My.Resources.ImportXMLHS)
        mnuViewLog = New ToolStripMenuItem("View Log File", My.Resources.OpenFile)
        mnuHelp = New ToolStripMenuItem("WRDBTasks User's Guide", My.Resources.Help)
        mnuAutoStart = New ToolStripMenuItem("Start Automatically", My.Resources.PlayHS)
        mnuAutoStart.CheckOnClick = True

        mnuSep1 = New ToolStripSeparator()
        mnuExit = New ToolStripMenuItem("Exit", My.Resources._305_Close_16x16_72)
        MainMenu = New ContextMenuStrip
        MainMenu.Items.AddRange(New ToolStripItem() {mnuArchives, mnuImport, mnuViewLog, mnuHelp, mnuAutoStart, mnuSep1, mnuExit})

        mnuAutoStart.Checked = ShortCutExists(WRDBShortcut, Environment.SpecialFolder.Startup)

        ''put in startup folder
        'If Not ShortCutExists("WRDB Scheduled Tasks", Environment.SpecialFolder.Startup) Then
        '    If MessageBox.Show("The WRDB Task Scheduler is now running (see the icon in the notification area of the Windows taskbar). Do you want to start the WRDB Task Scheduler every time you restart Windows?" & vbCrLf & vbCrLf & "If you click 'Yes', a shortcut will be added to the 'Startup' folder of your Start menu to make the WRDB Task Scheduler run each time you restart your computer. Simply remove that shortcut if you no longer wish to automatically run the Scheduler." & vbCrLf & vbCrLf & "If you click 'No', the Task Scheduler will run now until you exit the application or restart your computer." & vbCrLf & vbCrLf & "WARNING: in a networked configuration, only a SINGLE user should install and use this application.", "WRDB Task Scheduler", MessageBoxButtons.YesNo) = DialogResult.Yes Then
        '        Try
        '            CreateShortcut("WRDB Scheduled Tasks", Application.ExecutablePath, Environment.SpecialFolder.Startup)
        '        Catch ex As Exception
        '            MessageBox.Show("Unable to create a shortcut to the WRDBTasks application in the Startup menu, so this application will not be automatically started when Windows restarts.")
        '        End Try
        '    End If
        'End If

        AutoBackupActivated = GetKey(enumTaskKey.BackupActivated, False)
        AutoBackupFolder = GetKey(enumTaskKey.Folder, MyDataPath() & "\Archives")
        AutoBackupTime = GetKey(enumTaskKey.BackupTime, "04:00")

        AutoImportActivated = GetKey(enumTaskKey.ImportActivated, False)
        For Each s In GetKey(enumTaskKey.ImportTime, "03:00").Split(New Char() {" ", ",", ";"}, StringSplitOptions.RemoveEmptyEntries)
            If IsDate(s) Then AutoImportTimeList.Add(CDate(s))
        Next

        'Initialize the tray
        Tray = New NotifyIcon
        Tray.Icon = My.Resources.Wrdb 'this must be 16x16 to look good in tray; use WRDBTasks icon for forms to look good on taskbar
        Tray.ContextMenuStrip = MainMenu
        ResetShortcutTooltip()

        'Display
        Tray.Visible = True

        LogFile = MyDataPath() & "\WRDBTasks.log"
        'allow single instance only
        If Process.GetProcessesByName(Process.GetCurrentProcess.ProcessName).Length() > 1 Then
            AppendLog($"WRDBTasks Version {My.Application.Info.Version.ToString(4)} application started but then automatically shut down to prevent multiple instances from running.")
            End
        Else
            AppendLog($"WRDBTasks Version {My.Application.Info.Version.ToString(4)} application started (build date {System.IO.File.GetLastWriteTime(Me.GetType().Assembly.Location).ToString("g", Globalization.CultureInfo.InvariantCulture)}).")
            AppendLog($">>>Auto Backup Activated: {AutoBackupActivated}; Time: {AutoBackupTime:HH:mm}; Folder: {AutoBackupFolder}")
            AppendLog($">>>Auto Import Activated: {AutoImportActivated}; Time: {AutoImportTimeList:HH:mm}")
        End If

        With TaskTimer
            .Interval = 60000
            .Start()
        End With

        If Debugger.IsAttached Then mnuImport.PerformClick()
    End Sub

#End Region

#Region " Event handlers "

    Private Sub AppContext_ThreadExit(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.ThreadExit
        'Guarantees that the icon will not linger.
        Tray.Visible = False
    End Sub

    Private Sub ResetShortcutTooltip()
        Dim s = ""
        For Each t In AutoImportTimeList
            s &= IIf(s = "", "", ", ") & t.ToString("HH:mm")
        Next
        SetTrayText(WRDBShortcut &
                    IIf(AutoBackupActivated, vbCr & "Backups at: " & AutoBackupTime.ToString("HH:mm"), "") &
                    IIf(AutoImportActivated, vbCr & "Imports at: " & s, ""))
    End Sub

    Private Sub mnuArchives_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuArchives.Click
        Try

            With New frmArchiveScheduled
                Dim res = .ShowDialog()
                If res <> DialogResult.Cancel Then
                    AutoBackupActivated = .chkActivate.Checked
                    AutoBackupFolder = .txtFolder.Text
                    AutoBackupTime = .txtTime.Text
                    ResetShortcutTooltip()
                    TaskTimer.Stop()

                    Select Case res
                        Case DialogResult.OK
                            AppendLog($"Archive options updated.  Activated: {AutoBackupActivated}; Time: {AutoBackupTime:HH:mm}; Folder: {AutoBackupFolder}")
                        Case DialogResult.Yes
                            AppendLog($"Archive manually started by {Environment.UserName}.")
                            RunBackup(True)
                    End Select
                End If
            End With

        Catch ex As Exception

            ErrorMsg(, ex)

        Finally

            TaskTimer.Start()

        End Try

    End Sub

    Private Sub mnuImport_Click(sender As Object, e As EventArgs) Handles mnuImport.Click
        Try

            With New frmImportScheduled
                Dim res = .ShowDialog()
                If res <> DialogResult.Cancel Then
                    AutoImportActivated = .chkActivate.Checked
                    AutoImportTimeList.Clear()
                    For Each s In GetKey(enumTaskKey.ImportTime, "03:00").Split(New Char() {" ", ",", ";"}, StringSplitOptions.RemoveEmptyEntries)
                        If IsDate(s) Then AutoImportTimeList.Add(CDate(s))
                    Next
                    TaskTimer.Stop()

                    Select Case res
                        Case DialogResult.OK
                            AppendLog($"Import options updated.  Activated: {AutoImportActivated}; Time: {AutoImportTimeList:HH:mm}")
                        Case DialogResult.Yes
                            AppendLog($"Import manually started by {Environment.UserName}.")
                            RunImport(True)
                    End Select
                    ResetShortcutTooltip()
                End If
            End With

        Catch ex As Exception

            ErrorMsg(, ex)

        Finally

            TaskTimer.Start()

        End Try

    End Sub

    Private Sub mnuViewLog_Click(sender As Object, e As EventArgs) Handles mnuViewLog.Click
        Try

            Process.Start(LogFile)

        Catch ex As Exception

            ErrorMsg(, ex)

        End Try
    End Sub

    Private Sub mnuHelp_Click(sender As Object, e As EventArgs) Handles mnuHelp.Click
        Try

            Dim FileName As String = clsProject.HelpFilePath("WRDBTasks.pdf")
            If Not My.Computer.FileSystem.FileExists(FileName) Then
                WarningMsg($"Unable to find help file named '{FileName.Replace("\", "\\")}'; please restore this file or reinstall application.")
            Else
                Process.Start(FileName)
            End If

        Catch ex As Exception

            ErrorMsg(, ex)

        End Try
    End Sub

    Private Sub mnuAutoStart_Click(sender As Object, e As EventArgs) Handles mnuAutoStart.Click
        DeleteShortCut(WRDBShortcutOld, Environment.SpecialFolder.Startup)
        DeleteShortCut(WRDBShortcut, Environment.SpecialFolder.Startup)
        If mnuAutoStart.Checked Then
            Try
                CreateShortcut(WRDBShortcut, Application.ExecutablePath, Environment.SpecialFolder.Startup)
                AppendLog("Shortcut to application added to startup path.")
            Catch ex As Exception
                MessageBox.Show("Unable to create a shortcut to the WRDBTasks application in the Startup menu, so this application will not be automatically started when Windows restarts.")
            End Try
        End If
    End Sub

    Private Sub mnuExit_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles mnuExit.Click
        If MessageBox.Show("If you close this application, scheduled archives and imports that have been configured will no longer occur. Are you sure you want to exit?", "WRDB Scheduled Tasks", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) = DialogResult.Yes Then
            AppendLog("Application closed by user.")
            Application.Exit()
        End If
    End Sub

    ''' <summary>
    ''' If auto backup is enabled, then this will start the backup at the appropriate time
    ''' </summary>
    Private Sub TaskTimer_Tick(sender As Object, e As System.EventArgs) Handles TaskTimer.Tick
        Try
            AppendLog($"Timer activated")

            TaskTimer.Stop()
            If AutoBackupActivated Then RunBackup(False)
            'note: if imports scheduled to run before backups are finished, they will not run
            If AutoImportActivated Then RunImport(False)

        Catch ex As Exception
            AppendLog("Error occurred during automatic archive/import: {0}.", ex.Message)
            SetTrayText("WRDB error occurred; check settings and log file")
        Finally
            TaskTimer.Start()
        End Try
    End Sub

    Private Sub RunBackup(RunNow As Boolean)
        Try

            If Not My.Computer.FileSystem.DirectoryExists(AutoBackupFolder) Then My.Computer.FileSystem.CreateDirectory(AutoBackupFolder)

            If RunNow Or (Now.Hour = AutoBackupTime.Hour AndAlso Now.Minute = AutoBackupTime.Minute) Then

                If Not RunNow Then AppendLog($"Automatic backup task started on machine owned by {Environment.UserName}")

                Dim ProjNum As Integer = 0
                Dim lstProj As Generic.Dictionary(Of String, String) = Nothing
                lstProj = clsConnections.GetProjectList()

                ImportProgressForm = New frmProgress
                ImportProgressForm.lblProgress.Text = "Initiating Archive..."
                ImportProgressForm.Show()

                For Each Projectname As String In lstProj.Keys
                    Try
                        Dim Project As clsProject = Nothing
                        Try
                            SetTrayText("Checking project: {0}...", Projectname)
                            Project = New clsProject(Projectname)
                        Catch ex As Exception
                            AppendLog("Unable to open project: {0}.", Projectname)
                            Throw
                        End Try

                        If Project.IncludeInBackup Then
                            CurrentProject = Project.Name
                            SetTrayText("Archiving project: {0}...", CurrentProject)
                            Dim TempZipPath As String = clsProject.TempPath & "\zip"
                            If My.Computer.FileSystem.DirectoryExists(TempZipPath) Then My.Computer.FileSystem.DeleteDirectory(TempZipPath, FileIO.DeleteDirectoryOption.DeleteAllContents)
                            My.Computer.FileSystem.CreateDirectory(TempZipPath)

                            Dim tbllist As List(Of String) = Project.GetTableListAll
                            For t = 0 To tbllist.Count - 1
                                Dim TableName = tbllist(t)
                                ImportProgressForm.ProgressBar1.Value = t * 100.0 / (tbllist.Count - 1)
                                If ImportProgressForm.IsCancelled Then Exit Sub
                                SetTrayText("Archiving project: {0}; exporting table: {1}...", CurrentProject, TableName)
                                If Not Project.ExportTable(TableName, TempZipPath & "\" & TableName & ".txt") Then
                                    AppendLog("Unable to export table: {0}", TableName)
                                    Continue For
                                End If
                            Next

                            If Not My.Computer.FileSystem.DirectoryExists(AutoBackupFolder) Then My.Computer.FileSystem.CreateDirectory(AutoBackupFolder)

                            Dim ZipFile As String = String.Format("{0}\{1} Backup-{2:yyyyMMdd}.zip", AutoBackupFolder, Project.Name, Now.Date)

                            Try
                                SetTrayText("Archiving project: {0}; creating zip file: {1}...", CurrentProject, ZipFile)
                                ArchiveFolderContents(ZipFile, TempZipPath)
                                AppendLog("Created archive: {0}.", ZipFile)
                            Catch ex As Exception
                                AppendLog("Error occurred while creating archive: " & ZipFile & "--" & ex.Message)
                                SetTrayText("An error occurred; check your settings and log file.")
                                Throw
                            End Try
                        End If
                        ProjNum += 1
                    Catch ex As Exception
                        'error occurred, just ignore and continue
                        AppendLog("Error occurred while processing project: {0}--{1}", Projectname, ex.Message)
                        SetTrayText("An error occurred; check your settings and log file.")
                        Throw
                    End Try

                    If ImportProgressForm.IsCancelled Then Exit For

                Next
                ResetShortcutTooltip()
            End If


        Catch ex As Exception

            MessageBox.Show(StringFormat("An unexpected error occurred while running the WRDB task: {0}", ex.Message))

        Finally

            If ImportProgressForm IsNot Nothing Then
                ImportProgressForm.Close()
                ImportProgressForm.Dispose()
                ImportProgressForm = Nothing
            End If

        End Try

    End Sub

    Private Function TimeToRun() As Boolean
        For Each t In AutoImportTimeList
            If Now.Hour = t.Hour And Now.Minute = t.Minute Then Return True
        Next
        Return False
    End Function

    Private Sub RunImport(RunNow As Boolean)
        Try

            IsCancelled = False

            If RunNow Or TimeToRun() Then

                If Not RunNow Then AppendLog($"Automatic import task started on machine owned by {Environment.UserName}")

                Dim NumConnections As Integer = GetKey(enumTaskKey.NumConnections, 0)
                Dim lstImports As New List(Of clsImport)
                For i As Integer = 0 To NumConnections - 1
                    Dim SectionName As String = "Connection_" & i
                    Dim Import As clsImport = clsImport.GetImport(SectionName)
                    If Import IsNot Nothing Then
                        Import.Load(SectionName)
                        lstImports.Add(Import)
                    End If
                Next

                'show progress form
                ImportProgressForm = New frmProgress
                ImportProgressForm.Show()

                Dim ImportErrors As Boolean = False

                For Each import As clsImport In lstImports
                    If import.Activated Then
                        SetTrayText($"Importing connection: {import.ConnectionName}...")
                        ImportProgressForm.lblProgress.Text = $"Initiating Import for {import.ConnectionName}..."
                        import.Import()
                        If import.ErrorsOccurred Then ImportErrors = True
                    Else
                        AppendLog($"Import for connection named {import.ConnectionName} bypassed because it is not active.")
                    End If
                Next

                If ImportErrors Then
                    SetTrayText("WRDB error occurred; check settings and log file")
                Else
                    ResetShortcutTooltip()
                End If
            End If

        Catch ex As Exception

            MessageBox.Show(StringFormat("An unexpected error occurred while running the WRDB task: {0}", ex.Message))

        Finally

            If ImportProgressForm IsNot Nothing Then
                ImportProgressForm.Close()
                ImportProgressForm.Dispose()
                ImportProgressForm = Nothing
            End If

        End Try

    End Sub

    Private Sub ArchiveFolderContents(ZipFile As String, FolderName As String)
        Dim fze As New ICSharpCode.SharpZipLib.Zip.FastZipEvents
        fze.Progress = New ICSharpCode.SharpZipLib.Core.ProgressHandler(AddressOf ZipProgress)
        Dim fz As New ICSharpCode.SharpZipLib.Zip.FastZip(fze)
        fz.CreateZip(ZipFile, FolderName, False, "", "")
        My.Computer.FileSystem.DeleteDirectory(FolderName, FileIO.DeleteDirectoryOption.DeleteAllContents)
    End Sub

    Private Sub ZipProgress(sender As Object, e As ICSharpCode.SharpZipLib.Core.ProgressEventArgs)
        SetTrayText(String.Format("Archiving project {0} ({1}%)...", CurrentProject, e.PercentComplete))
    End Sub

#End Region

End Class
